from typing import Union
from mathutils import Vector
from bpy.app.translations import pgettext_iface as iface_
from bpy.types import Context, UILayout, Material, ShaderNode, GeometryNodeGroup


def title_header(col, title: str):
    header = col.box().row(align=True)
    header.alignment = 'CENTER'
    header.label(text=title)


def button_prop_with_without_icon(icon_add, button_settings):
    if button_settings["icon"]:
        icon_add.prop(
            button_settings["from"],
            button_settings["prop"],
            text=button_settings["text"],
            toggle=button_settings["toggle"],
            expand=button_settings["expand"],
            icon=button_settings["icon"],
        )
    else:
        icon_add.prop(
            button_settings["from"],
            button_settings["prop"],
            toggle=button_settings["toggle"],
            expand=button_settings["expand"],
            text=button_settings["text"]
        )

    if "scale_x" in button_settings:
        icon_add.scale_x = button_settings["scale_x"]

    if "scale_y" in button_settings:
        icon_add.scale_y = button_settings["scale_y"]


def button_op_with_without_icon(icon_add, button_settings):
    if "depress" in button_settings:
        if button_settings["icon"]:
            icon_add.operator(
                button_settings["prop"],
                text=button_settings["text"],
                icon=button_settings["icon"], depress=button_settings["depress"]
            )
        else:
            icon_add.operator(
                button_settings["prop"],
                text=button_settings["text"], depress=button_settings["depress"]
            )
    else:
        if button_settings["icon"]:
            icon_add.operator(
                button_settings["prop"],
                text=button_settings["text"],
                icon=button_settings["icon"]
            )
        else:
            icon_add.operator(
                button_settings["prop"],
                text=button_settings["text"]
            )

    if "scale_x" in button_settings:
        icon_add.scale_x = button_settings["scale_x"]

    if "scale_y" in button_settings:
        icon_add.scale_y = button_settings["scale_y"]


def collapsable(
        layout, contain_prop, show_hide_str: str, mytext: str, myicon: str = None, align=True,
        button_settings1: dict[str, str] = {},
        button_settings2: dict[str, str] = {}, without_down_box:bool=False):

    layout = layout.column(align=True)
    show_hide = getattr(contain_prop, show_hide_str)

    header = layout.box()
    subheader = header.row(align=True)

    toggle = subheader.row(align=True)
    toggle.use_property_split = False
    toggle.alignment = 'LEFT'
    toggle.emboss = 'NONE'
    toggle.prop(contain_prop, show_hide_str, icon='DISCLOSURE_TRI_DOWN' if show_hide else 'DISCLOSURE_TRI_RIGHT', text="")

    if len(button_settings1) > 0:
        row = subheader.row(align=True)
        row.emboss = 'NORMAL'
        row.alignment = 'RIGHT'
        icon_add1 = row.row(align=True)
        icon_add2 = row.row(align=True)
        icon_add1.emboss = 'NORMAL'
        icon_add1.alignment = 'RIGHT'
        icon_add2.emboss = 'NORMAL'
        icon_add2.alignment = 'RIGHT'
        icon_add1.separator()

        if "enabled" in button_settings1:
            icon_add1.enabled = button_settings1["enabled"]

        if "enabled" in button_settings2:
            icon_add2.enabled = button_settings2["enabled"]

        if button_settings1["type"] == "prop":
            button_prop_with_without_icon(icon_add1, button_settings1)
            if len(button_settings2) > 0:
                button_prop_with_without_icon(icon_add2, button_settings2)

        elif button_settings1["type"] == "operator":
            button_op_with_without_icon(icon_add1, button_settings1)
            if len(button_settings2) > 0:
                button_op_with_without_icon(icon_add2, button_settings2)
        
        elif button_settings1["type"] == "bool":
            prop_args_bt1 = {
                "text": button_settings1["text"],
                "icon": button_settings1["icon"] if "icon" in button_settings1 else None,
                "emboss": button_settings1["emboss"],
            }
            icon_add1.prop(button_settings1["from"], button_settings1["prop"], **prop_args_bt1)

    prop_args_icon = {"text": mytext, "icon": myicon} if myicon else {"text": mytext}
    toggle.prop(contain_prop, show_hide_str, **prop_args_icon)

    if without_down_box:
        return show_hide
    
    if show_hide:
        settings = layout.box().column(align=align)
        return settings


def cheker_item_visibility(fluidlab, layout):
    brush_list = fluidlab.brush_list
    item = brush_list.get_current_item()
    if item:
        return item.visibility
    else:
        return True


def multiline_print(layout: UILayout, text: str, max_words: int, icon: str = 'INFO') -> None:
    feedback = layout.box().column(align=True)
    words = text.split()
    for i in range(0, len(words), max_words):
        sentence = words[i:i+max_words]
        sentence = " ".join(sentence)
        if i == 0:
            feedback.label(text=sentence, icon=icon)
        else:
            feedback.label(text=sentence)


def horizontal_line_separator(layout: UILayout) -> UILayout:
    layout = layout.box().column(align=True)
    return layout


def get_ui_node(target_input, node_name: str) -> ShaderNode:
    # para poder acceder a todos los sub niveles que necesite:
    if node_name in target_input.node_tree.nodes:
        return target_input.node_tree.nodes[node_name]


def show_socket_input(socket):
    return hasattr(socket, "draw") and socket.enabled and not socket.is_linked


def auto_refresh_gn(node):
    # Para que se auto refresque el GN:
    node.update_tag()


def special_ui_element(context:Context, layout:UILayout, node:Union[Material, GeometryNodeGroup], data_path:list = []) -> None:

    if len(data_path) > 0:
        for i in range(len(data_path)):
            if i == 0:
                shader_node = get_ui_node(node, data_path[i])
            else:
                shader_node = get_ui_node(shader_node, data_path[i])

    # set "node" context pointer for the panel layout
    layout.context_pointer_set("node", shader_node)

    if hasattr(shader_node, "draw_buttons_ext"):
        shader_node.draw_buttons_ext(context, layout)
    elif hasattr(shader_node, "draw_buttons"):
        shader_node.draw_buttons(context, layout)

    # XXX this could be filtered further to exclude socket types
    # which don't have meaningful input values (e.g. cycles shader)
    value_inputs = [socket for socket in shader_node.inputs if show_socket_input(socket)]

    # print(shader_node.mapping.curves[0].points[0].location)
    if value_inputs:
        layout.separator()
        layout.label(text="Inputs:")
        for socket in value_inputs:
            row = layout.row()
            socket.draw(
                context,
                row,
                shader_node,
                iface_(socket.label if socket.label else socket.name, socket.bl_rna.translation_context),
            )

    # Solo si el curve es de GN:
    # Guardamos la info de la curva para saber si fue modificada y solo ejecutar el auto refresh de gn si cambió:
    if isinstance(node, GeometryNodeGroup):
        current_location = []
        for curve in shader_node.mapping.curves:
            for point in curve.points:
                current_location.append(point.location)

        wm = context.window_manager
        if shader_node.name not in wm:
            wm[shader_node.name] = list(current_location)

        # print("current_location", current_location)
        if shader_node.name in wm:
            stored_loc = [Vector((loc[:])) for loc in wm[shader_node.name]]
            if current_location != stored_loc:

                # print("SE EJECUTA", current_location, stored_loc)
                auto_refresh_gn(node)

                wm[shader_node.name] = list(current_location)
